package Cinema.Tests;

import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import Cinema.CinemaSystem;
import Cinema.Client;
import Cinema.User;
import Cinema.CinemaEntities.Movie;
import Cinema.CinemaEntities.Order;
import Cinema.CinemaEntities.Show;
import Cinema.DataLayer.DataManager;
import Cinema.DataLayer.IDataBackup;
import Cinema.DataLayer.XmlBackup;
import Exceptions.BadArgumentException;
import Exceptions.ObjectAlreadyExist;
import Exceptions.PaymentFailed;
import Exceptions.ShowExpierd;

public class SystemTests {

	private final String EMPTY_DATABASE = ".\\tests\\systemTest\\empty database";
	private final String EMPTY_DATABASE_RESULT = ".\\tests\\systemTest\\empty database\\result";
	private final String BASIC_DATABASE = ".\\tests\\systemTest\\basic database";
	private final String BASIC_DATABASE_RESULT = ".\\tests\\systemTest\\basic database\\result";
	private final String WITH_ORDER = ".\\tests\\systemTest\\with order database";
	private final String WITH_ORDER_RESULT = ".\\tests\\systemTest\\with order database\\result";

	@Before
	public void InitTests(){
		CinemaSystem.isTesting = true;
	}

	/**
	 * Here we test that the system can add users and login the existing users
	 */
	@Test
	public void AddUsersTest() {
		TestDataManager dataManager = new TestDataManager(new XmlBackup(EMPTY_DATABASE));
		Client client = new Client("user1", "a@a.com", dataManager);
		assertEquals(dataManager.getAllUsers().values().size() , 0);
		try {
			dataManager.addUser(client);
		} catch (ObjectAlreadyExist e) {
			assertTrue(false);
		}
		try {
			dataManager.addUser(client);
			assertTrue(false);
		} catch (ObjectAlreadyExist e) {
		}
		assertEquals(dataManager.getAllUsers().values().size() , 1);
		client = new Client("user1", "a@a.com", dataManager);
		try {
			dataManager.addUser(client);
			assertTrue(false);
		} catch (ObjectAlreadyExist e) {
		}

		client = new Client("user2", "a@a.com", dataManager);
		try {
			dataManager.addUser(client);
		} catch (ObjectAlreadyExist e) {
			assertTrue(false);
		}
		assertEquals(dataManager.getAllUsers().values().size() , 2);

		client = new Client("user3", "a@a.com", dataManager);
		try {
			dataManager.addUser(client);
		} catch (ObjectAlreadyExist e) {
			assertTrue(false);
		}
		assertEquals(dataManager.getAllUsers().values().size() , 3);

		String password = client.getPassword();
		assertSame(dataManager.getUser("user3", password), client);
		assertNull(dataManager.getUser("user4", password));
		assertNull(dataManager.getUser("user3", password + "a"));
		
		dataManager.doBackupNow(EMPTY_DATABASE_RESULT);

	}

	/**
	 * Here we try to order tickets to a movie
	 */
	@Test
	public void MakeOrderTest() {
		TestDataManager dataManager = new TestDataManager(new XmlBackup(BASIC_DATABASE));
		Client client = null;
		for(User user : dataManager.getAllUsers().values()){
			client = (Client) user;
			break;
		}
		assertNotNull(client);
		assertEquals(client.getOrders().size(), 0);

		Movie movie = dataManager.getMovies().get(0);
		assertNotNull(movie);
		String movieGenre =movie.getGenre();

		Show show = dataManager.GetShowsForMovie(movie).get(0);
		assertNotNull(show);

		try {
			client.tryToOrderPlaces(show, 3, 3);
		} catch (BadArgumentException e) {
			assertTrue(false);
		}

		assertEquals(client.getOrders().size(), 1);
		ArrayList<Movie> movies = client.getMoviesforSite(client.getSites().get(0));
		//now checking the after the order, the order of the movies is as expected.
		assertEquals(movies.get(0).getGenre(),movieGenre);  //checking that movies of favorite genre are returned.
		assertNotSame(movies.get(1).getGenre(),movieGenre);  //next is not the same genre

		try {
			client.tryToOrderPlaces(show, 8, 3);	// Order too many seats
		} catch (BadArgumentException e) {
			assertTrue(false);
		}
		assertEquals(client.getOrders().size(), 1);

		movie = dataManager.getMovies().get(1);
		show = dataManager.GetShowsForMovie(movie).get(1);
		try {
			client.tryToOrderPlaces(show,1, 0);	// Order too many seats
			client.tryToOrderPlaces(show,1, 0);	// Order too many seats
			client.tryToOrderPlaces(show,1, 0);	// Order too many seats
		} catch (BadArgumentException e) {
			assertTrue(false);
		}
		movies = client.getMoviesforSite(client.getSites().get(0));
		//now checking the after the order, the order of the movies is as expected.
		assertNotSame(movies.get(0).getGenre(),movieGenre);  //next is not the same genre
		assertEquals(movies.get(1).getGenre(),movieGenre);  //checking that movies of favorite genre are returned.
		
		dataManager.doBackupNow(BASIC_DATABASE_RESULT);
	}

	/**
	 * Here we try to cancel existing orders
	 */
	@Test
	public void CancelOrderTest() {
		TestDataManager dataManager = new TestDataManager(new XmlBackup(WITH_ORDER));
		Client client = null;
		for(User user : dataManager.getAllUsers().values()){
			client = (Client) user;
			break;
		}
		assertNotNull(client);
		assertEquals(client.getOrders().size(), 1);

		for (Order order : client.getOrders()){
			try {
				client.cancelOrder(order);
				break;
			} catch (ShowExpierd e) {
				assertTrue(false);
			} catch (PaymentFailed e) {
				assertTrue(false);
			} catch (BadArgumentException e) {
				assertTrue(false);
			}
		}
		assertEquals(client.getOrders().size(), 0);
		
		dataManager.doBackupNow(WITH_ORDER_RESULT);
	}

	private class TestDataManager extends DataManager{
		public TestDataManager(IDataBackup dataBackup){
			super(dataBackup);
		}

		public HashMap<String, User> getAllUsers(){
			return this.users;
		}
	
	}
}
